﻿using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Windows.Forms;

using Data.GameData;
using Data.GameData.Utils;

namespace GUIDialogs
{
    public partial class UnitDesign : BaseDialog
    {
        #region Attributes
        private Unit unit = null;
        #endregion

        #region Properties
        public Unit GeneratedUnit
        {
            get { return unit; }
            set { unit = value; }
        }
        #endregion

        #region Constructor
        public UnitDesign()
        {
            InitializeComponent();
            InitialiseDialog();
        }

        /// <summary>
        /// Setup the initial values for the dialog.
        /// </summary>
        protected void InitialiseDialog()
        {
            // Load the systems
            systemListBox.Items.AddRange(GameDataStore.GetShipSystemNames().ToArray());

            // Load unit classes
            unitClassComboBox.Items.Add("");
            unitClassComboBox.Items.AddRange(GameDataStore.GetShipClasses().OrderBy(sClass => sClass.MaxHull).ToArray());

            addComboBox.SelectedIndex = 0;
            unitTypeComboBox.SelectedIndex = 0;
            unitClassComboBox.SelectedIndex = 0;

            PopulateExistingDesigns();
        }
        #endregion

        #region BaseDialog Overrides
        /// <summary>
        /// Determine is the manditory data is correct on the form
        /// </summary>
        /// <returns>True if the data is correct, false if otherwise</returns>
        protected override bool IsValid()
        {
            return CalculateUnitStats();
        }

        /// <summary>
        /// Add a completed unit design to the active race design list.
        /// </summary>
        protected override void UpdateData()
        {
            unit.Name = classNameTextBox.Text;
            unit.ShipClass = unitClassComboBox.SelectedItem as ShipClass;
            unit.ClearLayout();
            unit.Parse(controlString.Text);

            Race.ActiveRace.AddDesign(unit);
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Update the current unit stats.
        /// </summary>
        /// <returns>If all of the validation checks pass or not.</returns>
        private bool CalculateUnitStats()
        {
            errorProvider.SetError(unitClassComboBox, "");
            errorProvider.SetError(classNameTextBox, "");
            errorProvider.SetError(hsTextBox, "");
            errorProvider.SetError(bestSpeedTextBox, "");

            if (unitClassComboBox.SelectedItem == null || unitClassComboBox.SelectedItem is string)
            {
                errorProvider.SetError(unitClassComboBox, "Unit class required.");
                return false;
            }

            bool allGood = true;

            Unit tempUnit = unit.Clone() as Unit;

            tempUnit.ClearLayout();
            tempUnit.Name = classNameTextBox.Text;
            tempUnit.ShipClass = unitClassComboBox.SelectedItem as ShipClass;
            tempUnit.Parse(controlString.Text);

            // Update Stats
            hsTextBox.Text = tempUnit.HullUsed.ToString();
            totalCostTextBox.Text = tempUnit.Cost.ToString();
            htkTextBox.Text = tempUnit.HTK.ToString();

            StarShip ship = tempUnit as StarShip;
            bestSpeedTextBox.Text = ship != null ? ship.BestSpeed.ToString() + " (" + ship.MaxShipSpeed.ToString() + ")" : "N/A";
            turnModeTextBox.Text = ship != null ? ship.TurnMode.ToString() : "N/A";

            // Validate
            if (tempUnit.HullUsed > tempUnit.ShipClass.MaxHull)
            {
                errorProvider.SetError(hsTextBox, "Max HS exceeded.");
                allGood = false;
            }

            if (ship.BestSpeed > ship.MaxShipSpeed)
            {
                errorProvider.SetError(bestSpeedTextBox, "Max speed exceeded.");
                allGood = false;
            }

            if (tempUnit.Name.Trim().Length == 0)
            {
                errorProvider.SetError(classNameTextBox, "The class must have a name.");
                allGood = false;
            }

            return allGood;
        }

        /// <summary>
        /// Update the existing designs list based on the class selection.
        /// </summary>
        private void PopulateExistingDesigns()
        {
            existingDesignsListBox.Items.Clear();

            if (unitClassComboBox.SelectedItem == null || unitClassComboBox.SelectedItem is string)
                existingDesignsListBox.Items.AddRange(Race.ActiveRace.GetDesigns().ToArray());
            else
                existingDesignsListBox.Items.AddRange(Race.ActiveRace.GetDesignsForClass((unitClassComboBox.SelectedItem as ShipClass).ShortClassName).ToArray());
        }
        #endregion

        #region Dialog Callbacks
        #region Button callbacks
        /// <summary>
        /// Update the unit stats when the user presses the Validate button.
        /// </summary>
        /// <param name="sender">The gadget activated</param>
        /// <param name="e">The event args</param>
        private void validateButton_Click(object sender, EventArgs e)
        {
            CalculateUnitStats();
        }

        /// <summary>
        /// Add the selected number of systems to the current unit.
        /// </summary>
        /// <param name="sender">The gadget activated</param>
        /// <param name="e">The event args</param>
        private void addButton_Click(object sender, EventArgs e)
        {
            if (systemListBox.SelectedItem == null || generationListBox.SelectedItem == null)
                return;

            int numToAdd = int.Parse(addComboBox.SelectedItem as string);

            ShipSystem sys = generationListBox.SelectedItem as ShipSystem;
            for (int a = 0; a < numToAdd; ++a)
                controlString.Text += sys.Code;

            CalculateUnitStats();
        }

        /// <summary>
        /// Import a unit from a text file.
        /// </summary>
        /// <param name="sender">The gadget activated</param>
        /// <param name="e">The event args</param>
        private void importButton_Click(object sender, EventArgs e)
        {
            StreamReader file;
            openFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 1;
            openFileDialog.RestoreDirectory = true;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    if ((file = new StreamReader(openFileDialog.FileName)) != null)
                    {
                        string control = "";
                        using (file)
                        {
                            string line;
                            while ((line = file.ReadLine()) != null)
                                control += line;
                        }

                        controlString.Text = control;
                        CalculateUnitStats();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
                }
            }
        }

        /// <summary>
        /// Export the unit control string to a text file.
        /// </summary>
        /// <param name="sender">The gadget activated</param>
        /// <param name="e">The event args</param>
        private void exportButton_Click(object sender, EventArgs e)
        {
            StreamWriter file;
            openFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 1;
            openFileDialog.RestoreDirectory = true;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    if ((file = new StreamWriter(openFileDialog.FileName, false)) != null)
                    {
                        using (file)
                        {
                            file.WriteLine(controlString.Text);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: Could not write file. Original error: " + ex.Message);
                }
            }
        }

        /// <summary>
        /// Load a selected design into the dialog
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void loadButton_Click(object sender, EventArgs e)
        {
            Unit unitToLoad = existingDesignsListBox.SelectedItem as Unit;
            if (unitToLoad == null)
                return;

            unit = unitToLoad;

            if (unit is StarShip) unitTypeComboBox.SelectedIndex = 0;
            //if (unit is Base) unitTypeComboBox.SelectedIndex = 1;
            //if (unit is Starbase) unitTypeComboBox.SelectedIndex = 2;

            unitClassComboBox.SelectedIndex = unit.ShipClass.Size + 1;
            classNameTextBox.Text = unit.Name;

            unitClassComboBox_SelectedIndexChanged(unitClassComboBox, null);
            controlString.Text = unit.ControlString();

            CalculateUnitStats();
        }
        #endregion

        #region General callbacks
        /// <summary>
        /// When the user changes the selected ship system, update the system generation list.
        /// </summary>
        /// <param name="sender">The gadget activated</param>
        /// <param name="e">The event args</param>
        private void systemListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ExtListBox sysNames = sender as ExtListBox;
            if (sysNames == null)
                return;

            List<ShipSystem> genNames = GameDataStore.GetShipSystemGenerations(sysNames.SelectedItem as string);
            generationListBox.Items.Clear();
            generationListBox.Items.AddRange(genNames.ToArray());
            generationListBox.SelectedIndex = generationListBox.Items.Count - 1;
        }

        /// <summary>
        /// When the user changes the Unit type, create a new unit of the correct type.
        /// </summary>
        /// <param name="sender">The gadget activated</param>
        /// <param name="e">The event args</param>
        private void unitTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (unitTypeComboBox.SelectedText)
            {
                default:
                case "Starship":
                    unit = new StarShip(new ShipClass());
                    break;
                case "Base Station":
                    break;
                case "Starbase":
                    break;
            }

            controlString.Text = "";
        }

        /// <summary>
        /// When the user changes the Class of the Unit, update the class stats.
        /// </summary>
        /// <param name="sender">The gadget activated</param>
        /// <param name="e">The event args</param>
        private void unitClassComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ExtComboBox cBox = sender as ExtComboBox;
            if (cBox == null || unit == null)
                return;

            if (cBox.SelectedItem is string)
            {
                costTextBox.Text = "";
                minElTextBox.Text = "";
                minHsTextBox.Text = "";
                maxHsTextBox.Text = "";
            }
            else
            {
                ShipClass sClass = cBox.SelectedItem as ShipClass;

                costTextBox.Text = sClass.Cost.ToString();
                minElTextBox.Text = sClass.MinElLevel.ToString();
                minHsTextBox.Text = sClass.MinHull.ToString();
                maxHsTextBox.Text = sClass.MaxHull.ToString();
            }

            PopulateExistingDesigns();
        }
        #endregion
        #endregion
    }
}
